using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;

namespace ClassifierLib.Classifier.Filters
{
    /// <summary>
    /// If result of match filter is too small increase it by adding more rules
    /// </summary>
    public class Cover : RuleFilter
    {
        private int _threshold;

        public Cover()
        {
            Threshold = 5; // default value
            this.Name = "Cover";
            if (!RegisteredTypes.Contains(GetType()))
                RegisteredTypes.Add(GetType());
        }

        public Cover(int Threshold)
        {
            this.Threshold = Threshold;
        }

        public override Population Apply(Population Population, Population MatchSet, Environment.State State, Action Action)
        {
            // return prevous filter response if above threshold
            if (MatchSet.Count > Threshold)
                return MatchSet;

            //create covered classifier
            Rule newRule = CreateRuleFromState(State);


            // insert into vector of rules
            Population.AddIncNumerosity(newRule);
            // insert into selection
            MatchSet.Add(newRule);

            return MatchSet;

        }

        private Rule CreateRuleFromState(Environment.State State)
        {
            List<Double> upper = new List<Double>(State.Values.Count);
            List<Double> lower = new List<Double>(State.Values.Count);

            FindConditionBoundsFromState(State, upper, lower);

            // create condition from current environment state, with a random action output
            Rule newRule = new Rule(
                    new Condition(lower, upper),
                    ActionFactory.Instance()
                );

            ApplyRandomSettings(newRule);
            return newRule;
        }

        private static void FindConditionBoundsFromState(Environment.State State, List<Double> upper, List<Double> lower)
        {
            // create default values in arrays
            for (int i = 0; i < State.Values.Count; i++)
            {
                upper.Add(1);
                lower.Add(0);
            }

            for (int i = 0; i < State.Values.Count; i++)
            {
                int j = PersistantRandom.Instance.Next(State.Values.Count);
                bool isSpecialised = (j != 0); // 5 in 6 chance of specialising current condition for 6 bit MUX

                if (isSpecialised)
                {
                    upper[i] = State.Values[i];
                    lower[i] = State.Values[i];
                }
            }
        }

        private void ApplyRandomSettings(Rule Rule)
        {
            Rule.Statistics["prediction"] = PersistantRandom.Instance.Next(1000);
            Rule.Statistics["error"] = PersistantRandom.Instance.Next(1000);
            Rule.Statistics["fitness"] = PersistantRandom.Instance.NextDouble() * 1;
            Rule.Statistics["accuracy"] = PersistantRandom.Instance.NextDouble() * 1;
            Rule.Statistics["org_error"] = 0.95;
            Rule.Statistics["age"] = 0;
            Rule.Statistics["nicheSize"] = 1;
            Rule.Statistics["initIter"] = IterationCount;
            Rule.Statistics["lastIterationInGA"] = IterationCount;
        }

        /// <summary>
        /// This is the minumum number of matched rules before covering
        /// </summary>
        [CategoryAttribute("Settings"), Browsable(true), ReadOnly(false), BindableAttribute(false), DesignOnly(false), DescriptionAttribute("The minimum number of classifiers before adding rules")]
        public int Threshold
        {
            get
            {
                return _threshold;
            }
            set
            {
                _threshold = value;
                OnPropertyChanged("Threshold");
            }
        }
    }
}
